#pragma once
#include "Triangle3d.h"
#include "Line3d.h"
//#include "Point3d.h"
#include "Segment3d.h"
namespace Geometry
  {
  Triangle3d::Triangle3d(const Point3d& i_pt_1, const Point3d& i_pt_2, const Point3d& i_pt_3)
    : m_point_1(i_pt_1), m_point_2(i_pt_2), m_point_3(i_pt_3)
    {

    }

  Plane3d Triangle3d::GetPlane() const
    {
    Vector3d vector_1 = Vector3d(m_point_2[0] - m_point_1[0], m_point_2[1] - m_point_1[1], m_point_2[2] - m_point_1[2]);
    Vector3d vector_2 = Vector3d(m_point_3[0] - m_point_1[0], m_point_3[1] - m_point_1[1], m_point_3[2] - m_point_1[2]);

    return Plane3d(m_point_1, (vector_1 ^ vector_2));
    }

  bool Triangle3d::ContainsPoint(const Point3d& i_point) const
    {
    if (GetPlane().ContainsPoint(i_point) == false)
      return false;

    double det   = Geometry::determinant(Point3d(1, m_point_1[0], m_point_1[1]), Point3d(1, m_point_2[0], m_point_2[1]), Point3d(1, m_point_3[0], m_point_3[1]));
    double det_1 = Geometry::determinant(Point3d(1, i_point[0], i_point[1]),     Point3d(1, m_point_2[0], m_point_2[1]), Point3d(1, m_point_3[0], m_point_3[1]));
    double det_2 = Geometry::determinant(Point3d(1, m_point_1[0], m_point_1[1]), Point3d(1, i_point[0], i_point[1]),     Point3d(1, m_point_3[0], m_point_3[1]));
    double det_3 = Geometry::determinant(Point3d(1, m_point_1[0], m_point_1[1]), Point3d(1, m_point_2[0], m_point_2[1]), Point3d(1, i_point[0], i_point[1]));

    double m_1 = det_1 / det;
    double m_2 = det_2 / det;
    double m_3 = det_3 / det;

    if (m_1 >= 0 && m_2 >= 0 && m_3 >= 0)
      return true;

    return false;
    }

  Point3d Triangle3d::GetPoint1() const
    {
    return m_point_1;
    }

  Point3d Triangle3d::GetPoint2() const
    {
    return m_point_2;
    }
  
  Point3d Triangle3d::GetPoint3() const
    {
    return m_point_3;
    }

  bool SegmentProjectionIntersect(
    const Point3d& i_pt_1, const Point3d& i_pt_2, const Point3d& i_pt_3, const Point3d& i_pt_4,
    const Line3d& i_line
    )
    {
    Point3d pr_1 = i_line.GetProjection(i_pt_1);
    Point3d pr_2 = i_line.GetProjection(i_pt_2);
    Point3d pr_3 = i_line.GetProjection(i_pt_3);
    Point3d pr_4 = i_line.GetProjection(i_pt_4);

    Segment3d seg_1 = Segment3d(pr_1, pr_2);
    Segment3d seg_2 = Segment3d(pr_3, pr_4);

    Segment3d seg_11 = Segment3d(pr_1, pr_3);
    Segment3d seg_12 = Segment3d(pr_1, pr_4);

    Segment3d seg_21 = Segment3d(pr_3, pr_1);
    Segment3d seg_22 = Segment3d(pr_3, pr_2);

    if (seg_11.GetLength() + seg_12.GetLength() == seg_1.GetLength())
      return true;

    if (seg_21.GetLength() + seg_22.GetLength() == seg_2.GetLength())
      return true;

    return false;
    }

  bool SegmentIntersection(const Segment3d& i_seg_1, const Segment3d& i_seg_2)
    {
    Segment3d seg_11 = Segment3d(i_seg_1.GetBegin(), i_seg_2.GetBegin());
    Segment3d seg_12 = Segment3d(i_seg_1.GetBegin(), i_seg_2.GetEnd());

    Segment3d seg_21 = Segment3d(i_seg_2.GetBegin(), i_seg_1.GetBegin());
    Segment3d seg_22 = Segment3d(i_seg_2.GetBegin(), i_seg_1.GetEnd());

    if (seg_11.GetLength() + seg_12.GetLength() == i_seg_1.GetLength())
      return true;

    if (seg_21.GetLength() + seg_22.GetLength() == i_seg_2.GetLength())
      return true;

    return false;
    }
  
  Segment3d TriangleProjectLine3d(const Triangle3d i_tr, const Line3d& i_line)
    {
    Point3d pr_1 = i_line.GetProjection(i_tr.GetPoint1());
    Point3d pr_2 = i_line.GetProjection(i_tr.GetPoint2());
    Point3d pr_3 = i_line.GetProjection(i_tr.GetPoint3());

    double lng_12 = Segment3d(pr_1, pr_2).GetLength();
    double lng_23 = Segment3d(pr_2, pr_3).GetLength();
    double lng_31 = Segment3d(pr_3, pr_1).GetLength();

    if (lng_12 > lng_23)
      {
      if (lng_12 > lng_31)
        {
        return Segment3d(pr_1, pr_2);
        }
      else
        {
        return Segment3d(pr_3, pr_1);
        }
      }
    else
      {
      if (lng_31 > lng_23)
        {
        return Segment3d(pr_3, pr_1);
        }
      else
        {
        return Segment3d(pr_2, pr_3);
        }
      }
    }

  /*Segment3d Triangle3d::ProjectionLine3d(const Line3d& i_line) const
    {
    Point3d pr_1 = i_line.GetProjection(m_point_1);
    Point3d pr_2 = i_line.GetProjection(m_point_2);
    Point3d pr_3 = i_line.GetProjection(m_point_3);

    double lng_12 = Segment3d(pr_1, pr_2).GetLength();
    double lng_23 = Segment3d(pr_2, pr_3).GetLength();
    double lng_31 = Segment3d(pr_3, pr_1).GetLength();

    if (lng_12 > lng_23)
      {
      if (lng_12 > lng_31)
        {
        return Segment3d(pr_1, pr_2);
        }
      else
        {
        return Segment3d(pr_3, pr_1);
        }
      }
    else
      {
      if (lng_31 > lng_23)
        {
        return Segment3d(pr_3, pr_1);
        }
      else
        {
        return Segment3d(pr_2, pr_3);
        }
      }
    }*/
    
  bool Triangle3dIntesect(const Triangle3d& i_left, const Triangle3d& i_right)
    {

    // left-1
    Line3d line_1 = Line3d(i_left.GetPoint1(), i_left.GetPoint2());
    if (SegmentIntersection(TriangleProjectLine3d(i_left, line_1), TriangleProjectLine3d(i_right, line_1)) == false)
      return false;

    // left-2
    Line3d line_2 = Line3d(i_left.GetPoint2(), i_left.GetPoint3());
    if (SegmentIntersection(TriangleProjectLine3d(i_left, line_2), TriangleProjectLine3d(i_right, line_2)) == false)
      return false;
    // left-3
    Line3d line_3 = Line3d(i_left.GetPoint3(), i_left.GetPoint1());
    if (SegmentIntersection(TriangleProjectLine3d(i_left, line_3), TriangleProjectLine3d(i_right, line_3)) == false)
      return false;
    
    // right-1
    Line3d line_4 = Line3d(i_right.GetPoint1(), i_right.GetPoint2());
    if (SegmentIntersection(TriangleProjectLine3d(i_left, line_4), TriangleProjectLine3d(i_right, line_4)) == false)
      return false;
    // right-2
    Line3d line_5 = Line3d(i_right.GetPoint2(), i_right.GetPoint3());
    if (SegmentIntersection(TriangleProjectLine3d(i_left, line_5), TriangleProjectLine3d(i_right, line_5)) == false)
      return false;
    // right-3
    Line3d line_6 = Line3d(i_right.GetPoint3(), i_right.GetPoint1());
    if (SegmentIntersection(TriangleProjectLine3d(i_left, line_6), TriangleProjectLine3d(i_right, line_6)) == false)
      return false;
    return true;
    }

  }